/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.mapping;

import javax.sql.DataSource;

import org.apache.ibatis.transaction.TransactionFactory;

/**
 * Environment是MyBatis配置文件中标签environments 的映射，可以管理dataSource(连接信息)，transactionManager （事务管理器），如果下所示：
 *
 * <environments default="development">
 *     <environment id="development">
 *         <transactionManager type="JDBC"/>
 *         <dataSource type="POOLED">
 *             <property name="driver" value="com.mysql.jdbc.Driver"/>
 *             <property name="url" value="jdbc:mysql://localhost:3306/mbtest"/>
 *             <property name="username" value="root"/>
 *             <property name="password" value="123456"/>
 *         </dataSource>
 *     </environment>
 * </environments>
 *
 * 通过源码我们可以发现，在Environment类中有三个字段：id、transactionFactory、dataSource，分别对应于配置文件中的三个配置项（id、transactionManager、DataSource），
 * 而且这三项均为final类型，表示不可被更改，一次设置终身有效，所以在整个类中也只是使用三参构造器为三项字段赋值，而没有set方法可以进行字段值的更改，只有get方法，
 * 可以获取到设置的信息。
 *
 * Environment类内部有一个静态内部类Builder，这显然是一个构建器类，所以Environgment实例的创建使用了构建者模式（也叫建造者模式）。
 * 我们当然可以直接使用外部类的构造器直接进行实例创建，但这并不是MyBatis推荐的（当然其实也不会要求你去手动创建Environgment实例，这里只是打个比方），
 * MyBatis内部进行Environgment实例创建时，就是用其内部构建者进行创建，创建方式和源码中注释里一样：
 *
 * 这个实例的创建最显然的使用位置就是在XMLConfigBuilder构建器中解析构建Configuration类时在解析了Configuration.xml配置文件中environment标签的内容之后
 * 这个位置用于将读自于配置文件的配置信息配置到了Environment对象中。
 * 其实这个类很简单，但它内部包含的TracsactionFactory和DataSource这两个内容又是两大块内容，这一部分容后介绍。
 *
 */
public final class Environment {
  private final String id;
  private final TransactionFactory transactionFactory;
  private final DataSource dataSource;

  public Environment(String id, TransactionFactory transactionFactory, DataSource dataSource) {
    if (id == null) {
      throw new IllegalArgumentException("Parameter 'id' must not be null");
    }
    if (transactionFactory == null) {
      throw new IllegalArgumentException("Parameter 'transactionFactory' must not be null");
    }
    this.id = id;
    if (dataSource == null) {
      throw new IllegalArgumentException("Parameter 'dataSource' must not be null");
    }
    this.transactionFactory = transactionFactory;
    this.dataSource = dataSource;
  }

  //用法应该是new Environment.Builder(id).transactionFactory(xx).dataSource(xx).build();
  public static class Builder {
    private final String id;
    private TransactionFactory transactionFactory;
    private DataSource dataSource;

    public Builder(String id) {
      this.id = id;
    }

    public Builder transactionFactory(TransactionFactory transactionFactory) {
      this.transactionFactory = transactionFactory;
      return this;
    }

    public Builder dataSource(DataSource dataSource) {
      this.dataSource = dataSource;
      return this;
    }

    public String id() {
      return this.id;
    }

    public Environment build() {
      return new Environment(this.id, this.transactionFactory, this.dataSource);
    }

  }

  public String getId() {
    return this.id;
  }

  public TransactionFactory getTransactionFactory() {
    return this.transactionFactory;
  }

  public DataSource getDataSource() {
    return this.dataSource;
  }

}
